package jmine.tec.database.query.lazy;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * Referência lazy
 * 
 * @author lundberg
 * @param <V> tipo do valor
 */
public class Lazy<V> {

    private final FutureTask<V> task;

    /**
     * C'tor
     * 
     * @param callable the {@link Callable} that will generate the referent
     */
    public Lazy(Callable<V> callable) {
        this.task = new FutureTask<V>(callable);
    }

    /**
     * Obtém o valor, calculando caso necessário.
     * 
     * @return valor
     */
    public V get() {
        try {
            this.task.run();
            return this.task.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException(e);
        } catch (ExecutionException e) {
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            } else if (e.getCause() instanceof Error) {
                throw (Error) e.getCause();
            } else {
                throw new UndeclaredThrowableException(e.getCause());
            }
        }
    }

}
